package com.naiterui.ehp.bs.patient.controller.openapi;

import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.lang.Nullable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.naiterui.common.redis.RedisUtil;
import com.naiterui.ehp.bp.support.advice.IgnoreResponseEntityWrap;
import com.naiterui.ehp.bp.utils.beans.XmlMapper;
import com.naiterui.ehp.bp.utils.lang.ConfigUtil;
import com.naiterui.ehp.bp.utils.thread.ThreadPoolUtil;
import com.naiterui.ehp.bs.patient.constants.CacheConstant;
import com.naiterui.ehp.bs.patient.service.IWeChatMessageService;
import com.naiterui.ehp.bs.wechat.constants.WeChatConstant;
import com.naiterui.ehp.bs.wechat.service.ICustomMsgApiService;
import com.naiterui.ehp.bs.wechat.service.IWeChatService;

/**
 * @author zhoupeipei
 * @date 2019-06-12 18:13
 * @since 1.0.0
 */
@RequestMapping("ap/openapi")
@RestController
public class WeChatController {
    private static final Logger LOGGER = LoggerFactory.getLogger(WeChatController.class);

    @Autowired
    IWeChatService weChatService;
    @Autowired
    IWeChatMessageService weChatMessageService;
    @Autowired
    ICustomMsgApiService customMsgApiService;
    /**
     * 缓存锁有效期，10s
     */
    private static final int LOCK_TIME = 10;

    /**
     * @Description: 微信公众号后台服务器配置路径，接受微信服务端的验证、消息推送时间推送等
     * <p>
     * token检验：https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1472017492_58YV5 1.4开发者基本配置
     * 普通消息官方文档：https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140453
     * 事件消息官方文档：https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140454
     * <p>
     * 微信服务器在五秒内收不到响应会断掉连接，并且重新发起请求，总共重试三次。假如服务器无法保证在五秒内处理并回复
     * 如果开发者需要对用户消息在5秒内立即做出回应，即使用“发送消息-被动回复消息”接口向用户被动回复消息时，可以在
     * <p>
     * 公众平台官网的开发者中心处设置消息加密。开启加密后，用户发来的消息和开发者回复的消息都会被加密（但开发者通过客服
     * <p>
     * 接口等API调用形式向用户发送消息，则不受影响）。关于消息加解密的详细说明，请见“发送消息-被动回复消息加解密说明”。
     * @Author: zhoupeipei
     * @Date： 2019/1/28
     */
    @IgnoreResponseEntityWrap
    @RequestMapping("wechat")
    public String paCheckToken(String signature, String timestamp, String nonce, String echostr, @RequestBody @Nullable String xmlBody) {
        LOGGER.info("wechat回调信息，signature：{}；timestamp：{}；nonce：{}；echostr：{}；xmlBody：{}", signature, timestamp, nonce, echostr, xmlBody);
        // 服务器token校验
        if (StringUtils.isNotBlank(signature) && StringUtils.isNotBlank(timestamp) && StringUtils.isNotBlank(nonce) && StringUtils.isNoneBlank(
                echostr)) {
            return this.weChatService.checkToken(signature, timestamp, nonce, echostr);
        }
        //处理其他业务
        String resultXml = WeChatConstant.RESPONSE_SUCCESS;
        if (StringUtils.isNotBlank(xmlBody)) {
            Map<String, String> requestMap = XmlMapper.fromXml(xmlBody, Map.class);
            String msgId = requestMap.get("MsgId");
            String fromUser = requestMap.get("FromUserName");
            String createTime = requestMap.get("CreateTime");

            if (StringUtils.isNotBlank(msgId)) {
                // 推送统一客服消息文案
                customMsgApiService.sendSystemMsg(fromUser, ConfigUtil.getString("wachat.sysmsg.disclaimer"));
                //患者咨询框消息推送
                // EventUtil.publishEvent(new WxMsgEvent(requestMap));
                return resultXml;
            }

            // 缓存请求key
            String lockKey = CacheConstant.getWechatMessageLockKey(fromUser + "_" + createTime);
            Long lockResult = RedisUtil.valueOps().setNx(lockKey, fromUser);
            if (lockResult == 0) {
                LOGGER.info("重复消息请求，不再处理，请求信息:{}", xmlBody);
                return resultXml;
            }

            String msgType = requestMap.get("MsgType");
            if (WeChatConstant.XmlMsgType.EVENT.equals(msgType)) {
                // 事件处理逻辑,异步
                ThreadPoolUtil.execute(() -> this.weChatMessageService.handleEventMessage(fromUser, xmlBody));
            }
            //设置缓存失效时间  10s
            RedisUtil.keyOps().expire(lockKey, LOCK_TIME);

        }
        return resultXml;
    }

}
